package demoMod.anm2editor.ui;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.graphics.Color;
import demoMod.anm2editor.enums.LayerType;
import demoMod.anm2editor.fonts.FontKeys;
import demoMod.anm2editor.interfaces.ReloadStringsSubscriber;
import demoMod.anm2editor.localization.LocalizedStrings;
import demoMod.anm2editor.model.*;
import demoMod.anm2editor.utils.IdGenerator;
import demoMod.gdxform.abstracts.Container;
import demoMod.gdxform.core.FormManager;
import demoMod.gdxform.helpers.FontHelper;
import demoMod.gdxform.interfaces.Element;
import demoMod.gdxform.interfaces.KeyboardEventSubscriber;
import demoMod.gdxform.interfaces.MouseEventSubscriber;
import demoMod.gdxform.ui.*;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;

public class TrackPane extends Container<Element> implements MouseEventSubscriber, KeyboardEventSubscriber, ReloadStringsSubscriber {
    public static final String ID = "TrackPane";
    private final GScrollPane scrollPane;
    private final TrackInfoList trackInfoList = new TrackInfoList();
    private final Timeline timeline = (Timeline) FormManager.getInstance().getContainerById(Timeline.ID);
    private boolean mouseDown = false;
    private final GLabel label;

    public TrackPane() {
        setWidth(Gdx.graphics.getWidth() * 0.2F);
        setHeight(Gdx.graphics.getHeight() * 0.2F);
        setX(0);
        setY(20);
        setBackground(Color.WHITE.cpy());
        setBackground(Color.DARK_GRAY.cpy());
        setId(ID);
        scrollPane = new GScrollPane(0, 0, getWidth(), getHeight() - 20.0F, getWidth(), getHeight() * 2) {
            @Override
            public boolean scrolled(int amount) {
                if (!this.visible() || !this.enabled()) {
                    return false;
                }
                if (Gdx.input.isKeyPressed(Input.Keys.CONTROL_LEFT) || Gdx.input.isKeyPressed(Input.Keys.CONTROL_RIGHT)) {
                    if ((float)Gdx.input.getX() >= getSelfX(true) && (float)Gdx.input.getX() <= getSelfX(true) + this.getWidth() && (float)(Gdx.graphics.getHeight() - Gdx.input.getY()) >= getSelfY(true) && (float)(Gdx.graphics.getHeight() - Gdx.input.getY()) <= getSelfY(true) + this.getHeight()) {
                        List<Element> elements = this.getElements();

                        for(int i = elements.size() - 1; i >= 0; --i) {
                            Element element = elements.get(i);
                            if (element instanceof MouseEventSubscriber && ((MouseEventSubscriber)element).scrolled(amount)) {
                                return true;
                            }
                        }

                        return false;
                    }
                }
                return super.scrolled(amount);
            }
        };
        scrollPane.setBackground(Color.WHITE.cpy());
        scrollPane.setBackground(Color.DARK_GRAY.cpy());
        GVScrollBar vScrollBar = new GVScrollBar(0, 0, 10, getHeight());
        scrollPane.setVScrollBar(vScrollBar);
        addElement(scrollPane);
        trackInfoList.setCellHeight(((Timeline) FormManager.getInstance().getContainerById(Timeline.ID)).getTrackHeight());
        trackInfoList.setMaxSelectedItems(1);
        scrollPane.addElement(trackInfoList);
        setBorderWidth(1);
        setBorder(Color.LIGHT_GRAY.cpy());
        label = new GLabel(5.0F, getHeight() - 10.0F, getWidth(), 20.0F, FontHelper.getFont(FontKeys.SIM_HEI_16));
        List<String> strings = LocalizedStrings.getStrings(ID);
        label.setText(strings.get(4));
        addElement(label);
        LocalizedStrings.subscribe(this);
    }

    public TrackInfoList getTrackInfoList() {
        return trackInfoList;
    }

    public void deselect() {
        List<GList.ListCellRenderer<TrackInfoItem>> elements = trackInfoList.getElements();
        int index = 0;
        for (GList.ListCellRenderer<TrackInfoItem> element : elements) {
            if (element.isSelected()) {
                trackInfoList.setSelected(index, false);
            }
            index++;
        }
    }

    public void selectTrack(int index) {
        deselect();
        trackInfoList.setSelected(index, true);
    }

    public void addTrack(Track track) {
        Timeline timeline = (Timeline) FormManager.getInstance().getContainerById(Timeline.ID);
        TrackInfoItem trackInfoItem = new TrackInfoItem(getWidth(), trackInfoList.getCellHeight(), track, FontHelper.getFont(FontKeys.SIM_HEI_16), FontHelper.getFont(FontKeys.SIM_HEI_12));
        trackInfoItem.setId(Integer.toString(track.getId()));
        trackInfoList.addItem(trackInfoItem);
        if (scrollPane.getPlainHeight() < Project.currentProject.getTracks().size() * timeline.getTrackHeight()) {
            scrollPane.setPlainHeight(scrollPane.getPlainHeight() + timeline.getTrackHeight());
            timeline.getScrollPane().setPlainHeight(scrollPane.getPlainHeight());
        }
    }

    public void clearTrack() {
        for (Element element : trackInfoList.getElements()) {
            element.dispose();
        }
        trackInfoList.clear();
        scrollPane.setPlainHeight(getHeight() * 2);
        ((Timeline) FormManager.getInstance().getContainerById(Timeline.ID)).getScrollPane().setPlainHeight(getHeight() * 2);
        scrollPane.getVScrollBar().setProgress(0);
    }

    public GScrollPane getScrollPane() {
        return scrollPane;
    }

    @Override
    public void activate() {
        super.activate();
        this.setBorder(new Color(0.05882F, 0.33725F, 0.98431F, 1));
    }

    @Override
    public void deactivate() {
        super.deactivate();
        this.setBorder(Color.LIGHT_GRAY.cpy());
    }

    @Override
    public boolean keyDown(int keyCode) {
        return false;
    }

    @Override
    public boolean keyUp(int keyCode) {
        return false;
    }

    @Override
    public boolean keyTyped(char key) {
        return false;
    }

    public void newTrack(int spriteSheetId, Consumer<Track> callback) {
        List<String> strings = LocalizedStrings.getStrings(ID);
        TextInputWindow textInputWindow = new TextInputWindow(strings.get(0), "", FontHelper.getFont(FontKeys.SIM_HEI_14));
        textInputWindow.setConfirmCallback(text -> {
            List<String> options = new ArrayList<>();
            options.add(strings.get(1));
            options.add(strings.get(2));
            OptionWindow optionWindow = new OptionWindow(strings.get(3), options, FontHelper.getFont(FontKeys.SIM_HEI_14));
            optionWindow.setConfirmCallback(i -> {
                Track track;
                switch (i) {
                    case 0:
                    default:
                        track = new Track(LayerType.LAYER);
                        break;
                    case 1:
                        track = new Track(LayerType.NULL);
                        break;
                }
                track.setName(text);
                track.setId(track.getLayerType() == LayerType.LAYER ? IdGenerator.nextTrackId() : IdGenerator.nextNullId());
                track.setSpriteSheetId(spriteSheetId);
                for (Animation animation : Project.currentProject.getAnimations()) {
                    track.addContent(animation.getName(), new TrackContent().setKeyFrames(new ArrayList<>()));
                }
                Project.currentProject.getTracks().add(0, track);
                TrackInfoItem infoItem = new TrackInfoItem(trackInfoList.getWidth(), trackInfoList.getHeight(), track, FontHelper.getFont(FontKeys.SIM_HEI_16), FontHelper.getFont(FontKeys.SIM_HEI_12));
                trackInfoList.addItem(-1, infoItem);
                String animationName = Project.currentProject.getCurrentAnimation().getName();
                TrackContentItem contentItem = new TrackContentItem(animationName, track);
                timeline.getTrackContentList().addItem(-1, contentItem);
                int len = StatusBar.getMaxAnimationLength();
                if (len > 120) {
                    while (timeline.getScrollPane().getPlainWidth() < len * timeline.getCellWidth()) {
                        timeline.getScrollPane().setPlainWidth(timeline.getScrollPane().getPlainWidth() + 50 * timeline.getCellWidth());
                    }
                }
                Operation operation = new Operation() {
                    @Override
                    public void undo() {
                        Project.currentProject.getTracks().remove(track);
                        trackInfoList.removeItem(infoItem);
                        timeline.removeTrack(track);
                        if (track.getLayerType() == LayerType.LAYER) {
                            IdGenerator.setTrackId(track.getId());
                        } else if (track.getLayerType() == LayerType.NULL) {
                            IdGenerator.setNullId(track.getId());
                        }
                        GScrollPane scrollPane = ((TrackPane) FormManager.getInstance().getContainerById(TrackPane.ID)).getScrollPane();
                        if (scrollPane.getPlainHeight() - Project.currentProject.getTracks().size() * ((Timeline) FormManager.getInstance().getContainerById(Timeline.ID)).getTrackHeight() > 3 * ((Timeline) FormManager.getInstance().getContainerById(Timeline.ID)).getTrackHeight()) {
                            float plainHeight = scrollPane.getPlainHeight() - 3 * ((Timeline) FormManager.getInstance().getContainerById(Timeline.ID)).getTrackHeight();
                            if (plainHeight < FormManager.getInstance().getContainerById(Timeline.ID).getHeight() * 2) {
                                plainHeight = FormManager.getInstance().getContainerById(Timeline.ID).getHeight() * 2;
                            }
                            scrollPane.setPlainHeight(plainHeight);
                            timeline.getScrollPane().setPlainHeight(plainHeight);
                            int len = StatusBar.getMaxAnimationLength();
                            if (len > 120) {
                                timeline.getScrollPane().setPlainWidth((len + 50) * timeline.getCellWidth());
                            } else {
                                timeline.getScrollPane().setPlainWidth(120 * timeline.getCellWidth());
                            }
                        }
                    }

                    @Override
                    public void redo() {
                        Project.currentProject.getTracks().add(0, track);
                        trackInfoList.addItem(-1, infoItem);
                        timeline.getTrackContentList().addItem(-1, contentItem);
                        if (track.getLayerType() == LayerType.LAYER) {
                            IdGenerator.setTrackId(track.getId() + 1);
                        } else if (track.getLayerType() == LayerType.NULL) {
                            IdGenerator.setNullId(track.getId() + 1);
                        }
                        int len = StatusBar.getMaxAnimationLength();
                        if (len > 120) {
                            while (timeline.getScrollPane().getPlainWidth() < len * timeline.getCellWidth()) {
                                timeline.getScrollPane().setPlainWidth(timeline.getScrollPane().getPlainWidth() + 50 * timeline.getCellWidth());
                            }
                        }
                        GScrollPane scrollPane = ((TrackPane) FormManager.getInstance().getContainerById(TrackPane.ID)).getScrollPane();
                        if (scrollPane.getPlainHeight() < Project.currentProject.getTracks().size() * ((Timeline) FormManager.getInstance().getContainerById(Timeline.ID)).getTrackHeight()) {
                            scrollPane.setPlainHeight(scrollPane.getPlainHeight() + 3 * ((Timeline) FormManager.getInstance().getContainerById(Timeline.ID)).getTrackHeight());
                            timeline.getScrollPane().setPlainHeight(scrollPane.getPlainHeight() + 3 * ((Timeline) FormManager.getInstance().getContainerById(Timeline.ID)).getTrackHeight());
                        }
                    }
                };
                operation.setName(strings.get(0));
                ((HistoryPanel) FormManager.getInstance().getContainerById(HistoryPanel.ID)).addOperation(operation);
                if (scrollPane.getPlainHeight() < Project.currentProject.getTracks().size() * ((Timeline) FormManager.getInstance().getContainerById(Timeline.ID)).getTrackHeight()) {
                    scrollPane.setPlainHeight(scrollPane.getPlainHeight() + 3 * ((Timeline) FormManager.getInstance().getContainerById(Timeline.ID)).getTrackHeight());
                    ((Timeline) FormManager.getInstance().getContainerById(Timeline.ID)).getScrollPane().setPlainHeight(scrollPane.getPlainHeight() + 3 * ((Timeline) FormManager.getInstance().getContainerById(Timeline.ID)).getTrackHeight());
                }
                if (callback != null) {
                    callback.accept(track);
                }
            });
        });
    }

    @Override
    public boolean clickDown(int screenX, int screenY, int button) {
        mouseDown = (float)screenX >= this.getX(true) && (float)screenX <= this.getX(true) + this.getWidth() && (float)(Gdx.graphics.getHeight() - screenY) >= this.getY(true) && (float)(Gdx.graphics.getHeight() - screenY) <= this.getY(true) + this.getHeight();
        if (mouseDown) {
            FormManager.getInstance().moveToTop(this);
            List<Element> elements = this.getElements();
            for(int i = elements.size() - 1; i >= 0; --i) {
                Element element = elements.get(i);
                if (element instanceof MouseEventSubscriber && ((MouseEventSubscriber)element).clickDown(screenX, screenY, button)) {
                    return true;
                }
            }
            if (button == Input.Buttons.RIGHT) {
                GMenuList menuList = new GMenuList();
                menuList.setWidth(200.0F);
                menuList.setX(screenX);
                menuList.setY(Gdx.graphics.getHeight() - screenY);

                List<String> strings = LocalizedStrings.getStrings(ID);
                GMenuItem newTrack = new GMenuItem(menuList.getWidth(), menuList.getMenuItemHeight(), strings.get(0) + "...", FontHelper.getFont(FontKeys.SIM_HEI_14)) {
                    @Override
                    public void onClick() {
                        newTrack(0, null);
                    }
                };
                if (Project.currentProject.getCurrentAnimation() == null) {
                    newTrack.setEnabled(false);
                }
                newTrack.setSplitLine(false);
                menuList.addElement(newTrack);
                FormManager.getInstance().addContainer(menuList);
                FormManager.getInstance().moveToTop(menuList);
            }
            FormManager.getInstance().getEventHooks().setCurrentFocusedElement(this);
            return true;
        }
        return false;
    }

    @Override
    public boolean clickUp(int screenX, int screenY, int button) {
        if (!this.mouseDown) return false;

        this.mouseDown = false;
        List<Element> elements = this.getElements();

        for(int i = elements.size() - 1; i >= 0; --i) {
            Element element = elements.get(i);
            if (element instanceof MouseEventSubscriber && ((MouseEventSubscriber)element).clickUp(screenX, screenY, button)) {
                break;
            }
        }
        return true;
    }

    @Override
    public boolean mouseDragged(int screenX, int screenY) {
        List<Element> elements = getElements();
        for (int i=elements.size() - 1;i >= 0;i--) {
            Element element = elements.get(i);
            if (element instanceof MouseEventSubscriber) {
                if (((MouseEventSubscriber) element).mouseDragged(screenX, screenY)) {
                    ((Timeline)FormManager.getInstance().getContainerById(Timeline.ID)).getScrollPane().getVScrollBar().setProgress(scrollPane.getVScrollBar().getProgress());
                    return true;
                }
            }
        }
        return false;
    }

    @Override
    public boolean mouseMoved(int screenX, int screenY) {
        return false;
    }

    @Override
    public boolean scrolled(int amount) {
        if (!this.visible()) return false;
        List<Element> elements = getElements();
        for (int i=elements.size() - 1;i >= 0;i--) {
            Element element = elements.get(i);
            if (element instanceof MouseEventSubscriber) {
                if (((MouseEventSubscriber) element).scrolled(amount)) {
                    ((Timeline)FormManager.getInstance().getContainerById(Timeline.ID)).getScrollPane().getVScrollBar().setProgress(scrollPane.getVScrollBar().getProgress());
                    return true;
                }
            }
        }
        return false;
    }

    @Override
    public boolean moveToElementBorder(Element element) {
        return false;
    }

    @Override
    public boolean hasFocus() {
        return true;
    }

    @Override
    public void onReloadStrings() {
        List<String> strings = LocalizedStrings.getStrings(ID);
        label.setText(strings.get(4));
    }
}
